/******************************************************************************
 Move Networks Raw QVT Editing Library

 Provides some basic editing functionality for raw QVT objects, such as
 the ability to schedule a clip into an existing QVT.

 NOTE: All QVT objects used in the library are expected to be in a raw
 object form, NOT MN.QVT.QVT objects.  Typically this library is expected to
 be used before passing the QVT on to the player.  For example, you could
 fetch the QVT file as a string using MN.QVT.LoadQVT, then evaluate it
 using MN.EvalJSON and then use that object in these functions.
******************************************************************************/

// Schedules a clip to play in a QVT, overwriting existing scheduled content during that time.
// Returns the modified QVT.
//
// Preconditions:
//  - qvt is a raw QVT object (i.e. not MN.QVT.QVT object)
//  - clip is an object and must have at least a range member
//  - all QVT clips must have explicit start,end range (no open-ended QVTs)
//
// Parameters
// qvt - qvt in which to schedule clip
// clip - clip object to schedule
// start - offset at which to schedule clip (in seconds from QVT start).
//         End is determined using the clip's range
//
// TODO: What to do if start is past the end of all clips
MN.QVTEdit =
{
    ScheduleClip : function(qvt, clip, start)
    {
        if(!clip.range)
        {
            logError("clip error - no range");
            return null;
        }
        var range = MN.QVTEdit.ParseRange(clip.range);
        if(!range)
        {
            logError("clip error - invalid range " + range);
            return null;
        }
        // properties of the clip to be scheduled
        var insertDur = range[1] - range[0];
        var insertStart = start;
        var insertEnd = start + insertDur;

        var pos = 0; // keeps track of absolute time position within the QVT
        var clipsNew = []; // The new schedule
        for (var i=0; i < qvt.clips.length; i++)
        {
            var qvtClip = qvt.clips[i];
            var range = MN.QVTEdit.ParseRange(qvtClip.range);
            var clipStart = pos;
            var clipDur = range[1] - range[0];
            var clipEnd = clipStart + clipDur;

            // advance the absolute time position
            pos += clipDur;

            if(insertStart >= clipEnd || insertEnd <= clipStart) // new clip doesn't overlap
            {
                clipsNew = clipsNew.concat(qvt.clips[i]);
                continue;
            }
            if(insertStart == clipStart) // same start time; add the new clip, any clip shortening will be taken care of later
            {
                clipsNew = clipsNew.concat(clip);
            }
            else if(insertStart > clipStart) // gotta shorten the clip by making the end time earlier
            {
                var shortClip = MN.Update({}, qvtClip); // copy by value. since we're changing range, we don't want refs
                shortClip.range = range[0] + "," + (range[0] + insertStart - clipStart); // earlier end time
                clipsNew = clipsNew.concat(shortClip);
                clipsNew = clipsNew.concat(clip);
            }
            if(insertEnd < clipEnd) // gotta shorten the clip by making the start time later
            {
                var shortClip = MN.Update({}, qvtClip);
                shortClip.range = (range[1] - (clipEnd - insertEnd)) + "," + range[1]; // later start time
                clipsNew = clipsNew.concat(shortClip);
            }
        };
        qvt.clips = clipsNew;
        return qvt;
    },

    // Sets the content QMX URL for a given show.  Schedules a new clip into the QVT
    // at the show start time, with a range corresponding to the show duration
    // Note: The QMX file must be at least as long as the show duration
    SetShowContentURL : function(qvt, showNum, url)
    {
        var show = qvt.shows[showNum];
        var showStart = show.start;
        if(showNum+1 < qvt.shows.length)
            var showEnd = qvt.shows[showNum+1].start;
        else
            var showEnd = MN.QVTEdit.QVTDuration(qvt); // last show in the QVT
        var showDur = showEnd - showStart;
        var clip = {
            range: "0," + showDur
        }
        if(url) clip.url = url;
        return MN.QVTEdit.ScheduleClip(qvt, clip, showStart); // schedule the content during the show's timeframe
    },

    // Sets the content for all gap clips in a QVT with a QMX URL
    // returns the modified QVT.
    SetGapContentURL : function(qvt, url)
    {
        if(qvt.clips)
        {
            for (var i=0; i < qvt.clips.length; i++) {
                var clip = qvt.clips[i];
                if(!clip.url)
                    clip.url = url;
            };
        }
        return qvt;
    },

    // Sets the content for all empty shows (no title and description)
    // with a QMX URL.  Returns the modified QVT.
    SetEmptyShowsContentURL : function(qvt, url)
    {
        if(qvt.shows)
        {
            for (var i=0; i < qvt.shows.length; i++) {
                var show = qvt.shows[i];
                if(!show.title && !show.desc && !show.description)
                    MN.QVTEdit.SetShowContentURL(qvt, i, url);
            };
        }
        return qvt;
    },

    // Calculates the duration of a QVT file by adding up the duration of all its clips
    QVTDuration : function(qvt)
    {
        var dur = 0;
        for (var i=0; i < qvt.clips.length; i++) {
            var range = MN.QVTEdit.ParseRange(qvt.clips[i].range);
            dur += (range[1] - range[0]);
        };
        return dur;
    },

    // Parses a string in "start,end" range format into an array of floats [start, end]
    // returns null if the range is invalid
    ParseRange : function(range)
    {
        if(!range) return null;

        var rangeParts = range.split(',');
        var rangeStart = parseFloat(rangeParts[0]);
        var rangeEnd = parseFloat(rangeParts[1]);

        if(isNaN(rangeStart) || isNaN(rangeEnd)) return null;

        return [rangeStart, rangeEnd];
    }
}

